from rest_framework import serializers
from .models import TaskDefinition, Tasks
from django_celery_beat.models import PeriodicTask, CrontabSchedule, ClockedSchedule, IntervalSchedule
from django_celery_results.models import TaskResult
from utils.TaskUtils import parse_task_kwargs, parse_task_args, get_task_name_from_kwargs
from django.contrib.auth import get_user_model
import json

User = get_user_model()
import logging

logger = logging.getLogger('ywadmin')

class TasksSerializer(serializers.ModelSerializer):
    """任务序列化器"""
    creator = serializers.SerializerMethodField()
    updater = serializers.SerializerMethodField()
    enabled = serializers.BooleanField()

    def get_creator(self, obj):
        # 添加空值检查
        if hasattr(obj, 'creator') and obj.creator:
            return obj.creator.username
        return None
    
    def get_updater(self, obj):
        # 添加空值检查
        if hasattr(obj, 'updater') and obj.updater:
            return obj.updater.username
        return None

    def get_enabled(self, obj):
        # 添加空值检查
        return obj.enabled

    class Meta:
        model = Tasks
        fields = '__all__'
        read_only_fields = ['celery_task_id', 'creator', 'updater', 'create_time', 'update_time']

class IntervalScheduleSerializer(serializers.ModelSerializer):
    """间隔调度序列化器"""
    class Meta:
        model = IntervalSchedule
        fields = ['id', 'every', 'period']

class CrontabScheduleSerializer(serializers.ModelSerializer):
    """Crontab调度序列化器"""
    # 写入时：前端传递的字符串 'Asia/Shanghai' 会被 Django 自动转换为 ZoneInfo 对象存储到数据库
    # 读取时：Django 会自动将 ZoneInfo 对象转换为字符串 'Asia/Shanghai' 返回给前端
    timezone = serializers.CharField()
    
    class Meta:
        model = CrontabSchedule
        fields = ['id', 'minute', 'hour', 'day_of_week', 'day_of_month', 'month_of_year', 'timezone']

class ClockedScheduleSerializer(serializers.ModelSerializer):
    """时钟调度序列化器"""
    class Meta:
        model = ClockedSchedule
        fields = ['id', 'clocked_time']

class TaskDefinitionSerializer(serializers.ModelSerializer):
    """任务定义序列化器 - 支持嵌套创建调度"""
    creator = serializers.SerializerMethodField()
    updater = serializers.SerializerMethodField()
    tasks_count = serializers.SerializerMethodField()
    
    # 嵌套序列化调度信息(只读)
    crontab_detail = CrontabScheduleSerializer(source='crontab', read_only=True)
    interval_detail = IntervalScheduleSerializer(source='interval', read_only=True)
    clocked_detail = ClockedScheduleSerializer(source='clocked', read_only=True)
    
    # 用于创建/更新的调度数据(只写)
    crontab_data = serializers.DictField(write_only=True, required=False, allow_null=True)
    interval_data = serializers.DictField(write_only=True, required=False, allow_null=True)
    clocked_data = serializers.DictField(write_only=True, required=False, allow_null=True)

    def get_tasks_count(self, obj):
        return obj.tasks.count()

    def get_creator(self, obj):
        if hasattr(obj, 'creator') and obj.creator:
            return obj.creator.username
        return None
    
    def get_updater(self, obj):
        if hasattr(obj, 'updater') and obj.updater:
            return obj.updater.username
        return None
    
    def validate(self, attrs):
        """校验调度数据"""
        task_type = attrs.get('task_type')
        crontab_data = attrs.get('crontab_data')
        interval_data = attrs.get('interval_data')
        clocked_data = attrs.get('clocked_data')
        
        # 校验根据任务类型提供对应的调度数据
        if task_type == 'crontab' and not crontab_data:
            raise serializers.ValidationError('周期任务必须提供crontab_data')
        elif task_type == 'interval' and not interval_data:
            raise serializers.ValidationError('间隔任务必须提供interval_data')
        elif task_type == 'clock' and not clocked_data:
            raise serializers.ValidationError('时钟任务必须提供clocked_data')
        
        return attrs
    
    def create(self, validated_data):
        """创建任务定义及其调度"""
        # 提取调度数据
        crontab_data = validated_data.pop('crontab_data', None)
        interval_data = validated_data.pop('interval_data', None)
        clocked_data = validated_data.pop('clocked_data', None)
        task_type = validated_data.get('task_type')
        
        # 根据任务类型创建对应的调度
        if task_type == 'crontab' and crontab_data:
            # 尝试查找现有的crontab调度
            crontab = CrontabSchedule.objects.filter(**crontab_data).first()
            if not crontab:
                crontab = CrontabSchedule.objects.create(**crontab_data)
            validated_data['crontab'] = crontab
        
        elif task_type == 'interval' and interval_data:
            # 尝试查找现有的interval调度
            interval = IntervalSchedule.objects.filter(**interval_data).first()
            if not interval:
                interval = IntervalSchedule.objects.create(**interval_data)
            validated_data['interval'] = interval
        
        elif task_type == 'clock' and clocked_data:
            # 时钟任务总是创建新的
            clocked = ClockedSchedule.objects.create(**clocked_data)
            validated_data['clocked'] = clocked
        
        return super().create(validated_data)
    
    def update(self, instance, validated_data):
        """更新任务定义及其调度"""
        # 提取调度数据
        crontab_data = validated_data.pop('crontab_data', None)
        interval_data = validated_data.pop('interval_data', None)
        clocked_data = validated_data.pop('clocked_data', None)
        task_type = validated_data.get('task_type', instance.task_type)
        
        # 保存旧的调度以便后续清理
        old_crontab = instance.crontab
        old_interval = instance.interval
        old_clocked = instance.clocked
        
        # 清空所有调度
        instance.crontab = None
        instance.interval = None
        instance.clocked = None
        
        # 根据任务类型设置新的调度
        if task_type == 'crontab' and crontab_data:
            crontab = CrontabSchedule.objects.filter(**crontab_data).first()
            if not crontab:
                crontab = CrontabSchedule.objects.create(**crontab_data)
            instance.crontab = crontab
        
        elif task_type == 'interval' and interval_data:
            interval = IntervalSchedule.objects.filter(**interval_data).first()
            if not interval:
                interval = IntervalSchedule.objects.create(**interval_data)
            instance.interval = interval
        
        elif task_type == 'clock' and clocked_data:
            clocked = ClockedSchedule.objects.create(**clocked_data)
            instance.clocked = clocked
        
        # 更新其他字段
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        
        instance.save()
        
        # 清理旧的调度(如果不被其他使用)
        for old_schedule in [old_crontab, old_interval, old_clocked]:
            if old_schedule and old_schedule != instance.crontab and \
               old_schedule != instance.interval and old_schedule != instance.clocked:
                try:
                    if hasattr(old_schedule, 'taskdefinition_set') and \
                       not old_schedule.taskdefinition_set.exists():
                        old_schedule.delete()
                except Exception:
                    pass
        
        return instance

    class Meta:
        model = TaskDefinition
        fields = '__all__'
        read_only_fields = ['id', 'creator', 'updater', 'create_time', 'update_time']


class TaskResultSerializer(serializers.ModelSerializer):
    """任务结果序列化器"""
    # task_name = serializers.SerializerMethodField()
    status_display = serializers.SerializerMethodField()
    parsed_kwargs = serializers.SerializerMethodField()
    parsed_args = serializers.SerializerMethodField()
    
    def get_status_display(self, obj):
        status_map = {
            'SUCCESS': '成功',
            'FAILURE': '失败',
            'REVOKED': '取消',
            'STARTED': '进行中',
            'RETRY': '重试',
            'PENDING': '等待中'
        }
        return status_map.get(obj.status, obj.status)
        
    def get_parsed_kwargs(self, obj):
        """解析task_kwargs字段，处理多重序列化问题"""
        return parse_task_kwargs(obj.task_kwargs)
    
    def get_parsed_args(self, obj):
        """解析task_args字段，处理多重序列化问题"""
        return parse_task_args(obj.task_args)
    
    class Meta:
        model = TaskResult
        fields = ['id', 'task_id', 'task_name', 'periodic_task_name', 'date_created','status', 'status_display', 'date_done', 'result', 'traceback', 'task_args', 'task_kwargs', 'parsed_args', 'parsed_kwargs']
        read_only_fields = fields


##############  celery 内建模型序列化器
class PeriodicTaskSerializer(serializers.ModelSerializer):
    """周期任务序列化器"""
    class Meta:
        model = PeriodicTask
        fields = '__all__'

